package com.alan.camunda.boot.controller;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import jakarta.annotation.Resource;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.runtime.ProcessInstanceWithVariables;
import org.camunda.bpm.engine.runtime.UpdateProcessInstanceSuspensionStateSelectBuilder;
import org.glassfish.jersey.internal.guava.Lists;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/process")
public class ProcessController {
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private HistoryService historyService;


    @PostMapping("/startByDefKey")
    public String startByDefKey(String defKey, @RequestBody Map<String, Object> variables) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String bizKey = "ocap_" +sdf.format(new Date());



        ProcessInstance inst = runtimeService.startProcessInstanceByKey(defKey, bizKey, variables);
        if (inst.isEnded()) {
            return "Process instance is ended: " + inst.getId();
        }
        return "Process instance is started: " +inst.getId();
    }

    /**
     * 发起后返回流程变量，到流程等待状态
     */
    @PostMapping("/startWithReturn")
    public String startWithReturn(String defKey, @RequestBody Map<String, Object> variables) {
        ProcessInstanceWithVariables result = runtimeService.createProcessInstanceByKey(defKey)
                .setVariables(variables)
                .executeWithVariablesInReturn();

        return JSON.toJSONString(result.getVariables());
    }

    @PostMapping("/delete")
    public String delete(String insId) {
        runtimeService.deleteProcessInstance(insId, "delete by api");
        return "success";
    }


    @PostMapping("/startByDefKeyAndVariables")
    public String startByDefKeyAndVariables(@RequestParam String defKey, @RequestBody JSONObject variables) {
        ProcessInstance inst = runtimeService.startProcessInstanceByKey(defKey, variables);

        return "Start success, process instance id is :" + inst.getId();
    }




    @GetMapping("/deleteAll")
    public String terminateAll() {
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().active().list();
        for (ProcessInstance processInstance : list) {
            long count = runtimeService.createProcessInstanceQuery().active().processInstanceId(processInstance.getProcessInstanceId()).count();
            if (count == 1) {
                runtimeService.deleteProcessInstance(processInstance.getProcessInstanceId(), "Clear All");
            }
        }
        return "终止流程实例个数：" + list.size();
    }

    /**
     * 通过消息启动流程，同一个消息名称只能被一个流程定义使用，之后其他流程用这个MessageName启动无法部署
     *
     * @param message
     * @return
     */
    @GetMapping("/startByMessageAndDefId")
    public String startByMessageAndDefId(String message, String defId) {

        ProcessInstance processInstance = runtimeService.createMessageCorrelation(message)
                .processDefinitionId(defId)  // 指定版本
                .correlateStartMessage();

        return processInstance.getId();
    }

    /**
     * 默认使用该流程下最新的版本发起流程
     *
     * @param message
     * @return
     */
    @GetMapping("/startByMessage")
    public String startByMessage(String message) {

        ProcessInstance processInstance = runtimeService.createMessageCorrelation(message)
                .correlateStartMessage();

        return processInstance.getId();
    }


    @PostMapping("/suspend")
    public String suspend(String insId) {
        runtimeService.suspendProcessInstanceById(insId);

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(insId).singleResult();
        if (processInstance.isSuspended()) {
            return "Suspend success";
        } else {
            return "Suspend failed";
        }
    }

    /**
     * 挂起多个流程
     */
    @PostMapping("/suspend2")
    public String suspend2(String insId) {
        UpdateProcessInstanceSuspensionStateSelectBuilder builder = runtimeService.updateProcessInstanceSuspensionState();

        List<String> insIds = new ArrayList<>();
        insIds.add(insId);
        insIds.add("ABC");

        builder.byProcessInstanceIds(insIds).suspend();

        return "success";
    }

    @PostMapping("/suspendByRootInsId")
    public String suspend3(String insId) {
        List<ProcessInstance> list = runtimeService.createNativeProcessInstanceQuery()
                .sql("select id_ from ACT_HI_PROCINST where root_proc_inst_id_ = #{insId}")
                .parameter("insId", insId).list();

        List<String> list1 = list.stream().map(ProcessInstance::getId).toList();
        UpdateProcessInstanceSuspensionStateSelectBuilder builder = runtimeService.updateProcessInstanceSuspensionState();
        builder.byProcessInstanceIds(list1).suspend();

        return "success";
    }


    @PostMapping("/activate")
    public String activate(String insId) {
        runtimeService.activateProcessInstanceById(insId);


        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(insId).singleResult();
        if (processInstance != null) {
            if (!processInstance.isSuspended() && !processInstance.isEnded()) {
                return "activate success";
            } else {
                return "activate failed";
            }
        } else {
            HistoricProcessInstance inst = historyService.createHistoricProcessInstanceQuery().processInstanceId(insId).singleResult();
            if (inst != null) {
                return "activate failed, process instance is ended";
            } else {
                return "process instance not found";
            }
        }
    }

    @PostMapping("/activateByRootInsId")
    public String activateByRootInsId(String insId) {
        List<ProcessInstance> list = runtimeService.createNativeProcessInstanceQuery()
                .sql("select id_ from ACT_HI_PROCINST where root_proc_inst_id_ = #{insId}")
                .parameter("insId", insId).list();

        List<String> list1 = list.stream().map(ProcessInstance::getId).toList();
        UpdateProcessInstanceSuspensionStateSelectBuilder builder = runtimeService.updateProcessInstanceSuspensionState();
        builder.byProcessInstanceIds(list1).activate();

        return "success";
    }


}
